/*
 *  nss - glue to NSS certificate database
 *
 *  This file initially created by Google, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <inttypes.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

#define CONNMAN_API_SUBJECT_TO_CHANGE
#include <connman/plugin.h>
#include <connman/log.h>

#include <glib.h>

static const char *basename = "/tmp/nss-cert.";

static char *nss_get_certfile(const char *nickname, const uint8_t *id,
			      size_t id_len, gboolean is_pem)
{
        char *argv[] = { SCRIPTDIR "/nss-get-cert",
                         NULL,
                         NULL,
                         NULL,
                         NULL};
        int i, off, status;
        GError *error;
        char *filename;
        int cert_filename_length;
        char *mutable_nickname;
        char mutable_pem_arg[] = "pem";
        char mutable_der_arg[] = "der";

        cert_filename_length = strlen(basename) + 2 * id_len + 1;
        filename = g_malloc(cert_filename_length);
        strcpy(filename, basename);
        off = strlen(filename);
        for (i = 0; i < id_len; i++, off += 2)
                snprintf(&filename[off], 3, "%02x", id[i]);
        filename[cert_filename_length - 1] = '\0';

        mutable_nickname = g_strdup(nickname);

        argv[1] = mutable_nickname;
        argv[2] = is_pem ? mutable_pem_arg : mutable_der_arg;
        argv[3] = filename;

        if (!g_spawn_sync(
                        NULL,  /* working directory */
                        argv,
                        NULL,  /* envp */
                        0,     /* flags */
                        NULL,  /* child setup */
                        NULL,  /* child setup user data */
                        NULL,  /* child stdout */
                        NULL,  /* child stderr */
                        &status,  /* child exit status */
                        &error)) {
                connman_error("g_spawn_async() failure: %s",
                        error->message);
                g_error_free(error);
                g_free(filename);
                g_free(mutable_nickname);
                return NULL;
        }
        g_free(mutable_nickname);
        mutable_nickname = NULL;

        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
                g_free(filename);
                return NULL;
        }

        return filename;
}

char *nss_get_pem_certfile(const char *nickname, const uint8_t *id,
			   size_t id_len) {
        return nss_get_certfile(nickname, id, id_len, TRUE);
}

char *nss_get_der_certfile(const char *nickname, const uint8_t *id,
			   size_t id_len) {
        return nss_get_certfile(nickname, id, id_len, FALSE);
}

static int nss_init(void)
{
        return 0;
}

static void nss_exit(void)
{
        return;
}

CONNMAN_PLUGIN_DEFINE(nss, "NSS certificate glue", VERSION,
    CONNMAN_PLUGIN_PRIORITY_DEFAULT, nss_init, nss_exit)
